package com.duubee.btframe.auth.controller;

import com.alibaba.fastjson.JSONObject;
import com.duubee.btframe.auth.vo.AuthBody;
import com.duubee.btframe.auth.vo.AuthResponse;
import com.duubee.btframe.utils.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;

import java.text.MessageFormat;
import java.util.*;

@Slf4j
@RestController
@RequestMapping("/auth")
public class AuthController {

    @Value("${bt-auth.path}")
    private String path;

    @PostMapping("/computer")
    private AuthResponse computer(@RequestBody AuthBody authBody){

        if(!checkTimeLegality(authBody.getTimestamp())){
            //时间异常
            return AuthResponse.error(503);
        }

        //校验传输内容是否合法
        String encryptStr = MessageFormat.format("{0}|{1}|{2}|{3}|{4}|{5}",
                authBody.getApplicationName(),
                authBody.getIpAddress(),
                authBody.getTimestamp(),
                authBody.getContentPath(),
                authBody.getMachineCode(),
                authBody.getPort());

        String md5Str = BtEncryptUtil.md5(encryptStr);
        String timestamp = String.valueOf(authBody.getTimestamp());
        encryptStr = BtEncryptUtil.md5(MessageFormat.format("{0} - {1}",md5Str,timestamp));
        //判断加密字符串是否符合
        if(!(BtStringUtil.isNotEmpty(encryptStr) && encryptStr.equals(authBody.getEncryptStr()))){
            log.warn("error code: [{}], encryptStr:{} , data: {}",501,encryptStr,JSONObject.toJSONString(authBody));
            //加密字符串不符合则返回
            return AuthResponse.error(501);
        }

        //读取鉴权配置
        try {

            String auth = BtStreamUtil.readContentByPath(path);

            JSONObject authObject = JSONObject.parseObject(auth);

            //如果不存在机器码 或 enable 不为true 则提示无权限
            JSONObject userObject;
            if(!authObject.containsKey(authBody.getMachineCode()) || (((userObject = authObject.getJSONObject(authBody.getMachineCode())) == null) || !userObject.getBoolean("enable"))){

                log.warn("error code: [{}], data: {}",502,JSONObject.toJSONString(authBody));
                return AuthResponse.error(502);
            }
            //鉴权成功返回加密数据
            AuthResponse authResponse = new AuthResponse();
            authResponse.setUser(userObject.getString("user"));
            authResponse.setTimestamp(new Date().getTime());
            authResponse.setSuccess(true);
            authResponse.setEncryptStr(BtEncryptUtil.md5(BtEncryptUtil.AES.encrypt(MessageFormat.format("{0}|{1}|{2}",authResponse.getUser(),authBody.getMachineCode(),authBody.getEncryptStr()),String.valueOf(authResponse.getTimestamp()))));

            log.warn("error code: [{}], data: {} , auth response: {}",200,JSONObject.toJSONString(authBody),JSONObject.toJSONString(authResponse));
            return authResponse;

        }catch (Exception e){
            e.printStackTrace();
            log.warn("error code: [{}], data: {}",500,JSONObject.toJSONString(authBody));
            return AuthResponse.error(500);
        }


    }

    public static void main(String[] args) {
        String jsonObject = "{\"applicationName\":\"\",\"encryptStr\":\"ypISvpHXjf3aYhIXrEC+4vvE0kEoO9JHpu8LWCxhS54UMrnjxhgawmZ0OkkjdGq4\",\"ipAddress\":\"172.29.64.1\",\"machineCode\":\"f33b-3706-7dab-28b4-ead8-d73b-02ca-a422\",\"port\":8881,\"timestamp\":1618381429411}";

        AuthBody authBody = JSONObject.parseObject(jsonObject,AuthBody.class);

        String requestEncryptStr = authBody.getEncryptStr();
        authBody.setEncryptStr(null);
        //校验传输内容是否合法
        String encryptStr = BtEncryptUtil.AES.encrypt(BtEncryptUtil.md5(JSONObject.toJSONString(authBody)),String.valueOf(authBody.getTimestamp()));
        authBody.setEncryptStr(requestEncryptStr);
        System.out.println(encryptStr);
        System.out.println(!(BtStringUtil.isNotEmpty(encryptStr) && encryptStr.equals(requestEncryptStr)));

    }

    /**
     * 检测方法合理性
     * @param timestamp 时间戳
     * @return 是否合法
     */
    private boolean checkTimeLegality(long timestamp){

        Date date1 = BtDateUtil.timestampToDate(timestamp);
        Date date2 = new Date();
        long[] distance = BtDateUtil.getDistanceTime(date1,date2);

        distance[3] = 0;
        //如果计算机时间和服务器时间偏差30分钟以上 -- 返回false
        return !(distance[2] > 30 || Arrays.stream(distance).sum() > 30);
    }

    private static String getMachineCode(){

        Set<String> result = new HashSet<>();
        result.add(BtSystemUtil.getMac());
        result.add(BtSystemUtil.getCpuId());

        Properties props = System.getProperties();
        String javaVersion = props.getProperty("java.version");
        result.add(javaVersion);
        String javaVMVersion = props.getProperty("java.vm.version");
        result.add(javaVMVersion);
        String osVersion = props.getProperty("os.version");
        result.add(osVersion);
        result.add(String.valueOf(BtSystemUtil.getTotalPhysicalMemorySize()));



        return BtStringUtil.getSplitString(BtEncryptUtil.md5(result.toString()),"-",4);

    }


}
